package com.eastfair.venueservice.service.impl;

import cn.hutool.core.bean.BeanUtil;
//import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.eastfair.auth.api.AuthServiceFeign;
import com.eastfair.auth.api.UserAccountServiceFeign;
import com.eastfair.auth.dto.UserAccountDto;
import com.eastfair.auth.vo.OrganizationVo;
import com.eastfair.auth.vo.UserAccountVo;
import com.eastfair.boot.request.PageParams;
import com.eastfair.boot.service.SuperServiceImpl;
import com.eastfair.constant.BusinessConstant;
import com.eastfair.core.base.R;
import com.eastfair.core.context.ContextUtil;
import com.eastfair.core.exception.BizException;
import com.eastfair.core.utils.ExcelUtils;
import com.eastfair.projectcore.enumeration.DataIsolationSystemSceneEnum;
import com.eastfair.venueservice.dao.ServiceInventoryOutFlowMapper;
import com.eastfair.venueservice.dto.ExhibitionManageQuery;
import com.eastfair.venueservice.dto.ServiceInventoryOutFlowDTO;
import com.eastfair.venueservice.dto.ServiceInventoryOutFlowQuery;
import com.eastfair.venueservice.entity.ServiceInventory;
import com.eastfair.venueservice.entity.ServiceInventoryOutFlow;
import com.eastfair.venueservice.exceptioncode.VenueServiceExceptionCode;
import com.eastfair.venueservice.service.ExhibitionManageService;
import com.eastfair.venueservice.service.ServiceInventoryOutFlowService;
import com.eastfair.venueservice.service.ServiceInventoryService;
import com.eastfair.venueservice.service.ServiceProviderService;
import com.eastfair.venueservice.vo.ExhibitionManageVO;
import com.eastfair.venueservice.vo.ServiceInventoryOutFlowVO;
import com.eastfair.venueservice.vo.ServiceProviderVO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.util.Strings;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
* <p>
    * 业务实现类
    * 服务库存出库流水记录
    * </p>
*
* @author linan
* @date 2022-09-19
*/
@Slf4j
@Service
//@DS("#thread.tenant")
public class ServiceInventoryOutFlowServiceImpl extends SuperServiceImpl<ServiceInventoryOutFlowMapper, ServiceInventoryOutFlow> implements ServiceInventoryOutFlowService {

    @Resource
    private ServiceInventoryService serviceInventoryService;
    @Resource
    private UserAccountServiceFeign userAccountServiceFeign;

    @Resource
    private AuthServiceFeign authServiceFeign;

    @Resource
    private ServiceProviderService serviceProviderService;

    @Resource
    private ExhibitionManageService exhibitionManageService;

    /**
     * 处理逻辑删除相关处理
     *
     * @param modelList 实体
     * @return 是否成功
    */
    @Override
    protected R<Boolean> handlerRemoveByIdsOfLogic(Collection<ServiceInventoryOutFlow> modelList) {
    modelList.stream().forEach(s -> {
    s.setIsDeleted(BusinessConstant.YES);
    });
    // TODO: 2021/10/29 这里需要操作其他业务，如清空角色等
    return R.successDef();
    }

    @Override
    protected R<Boolean> handlerSave(ServiceInventoryOutFlow model) {
        model.setProjectId(ContextUtil.getProjectId());
        model.setSubsystemId(ContextUtil.getSubSystemId());
        return R.successDef();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean saveOutFlow(ServiceInventoryOutFlowDTO serviceInventoryOutFlowDTO) {
        // 查询原库存数量
        ServiceInventory serviceInventory = serviceInventoryService.getOne(new QueryWrapper<ServiceInventory>().lambda().eq(ServiceInventory::getInventoryCode, serviceInventoryOutFlowDTO.getInventoryCode()).eq(ServiceInventory::getIsDeleted, BusinessConstant.NO));
        // 封装要插入的流水数据
        ServiceInventoryOutFlow serviceInventoryOutFlow= BeanUtil.copyProperties(serviceInventoryOutFlowDTO,ServiceInventoryOutFlow.class);
        if(Objects.nonNull(serviceInventory)){
            serviceInventoryOutFlow.setBeforeInventoryNum(serviceInventory.getInventoryNum());
            serviceInventoryOutFlow.setAfterInventoryNum(serviceInventory.getInventoryNum().subtract(serviceInventoryOutFlowDTO.getOutNum()));

        }else {
            serviceInventoryOutFlow.setBeforeInventoryNum(BigDecimal.ZERO);
            serviceInventoryOutFlow.setAfterInventoryNum(serviceInventoryOutFlowDTO.getOutNum());
        }
        if (serviceInventoryOutFlow.getAfterInventoryNum().compareTo(BigDecimal.ZERO) < 0) {
            throw BizException.wrap(VenueServiceExceptionCode.INSUFFICIENT_INVENTORY);
        }
        boolean flag = save(serviceInventoryOutFlow);
        // 变更库存
        serviceInventoryService.minusInventory(serviceInventoryOutFlowDTO.getInventoryCode(),serviceInventoryOutFlowDTO.getOutNum());
        return flag;
    }

    @Override
    public Page<ServiceInventoryOutFlowVO> queryOutFlowList(PageParams<ServiceInventoryOutFlowQuery> serviceInventoryOutFlowQuery) {
        serviceInventoryOutFlowQuery.setSort(null);
        serviceInventoryOutFlowQuery.setOrder(null);
        Page<ServiceInventoryOutFlowQuery> serviceInventoryOutFlowQueryPage=serviceInventoryOutFlowQuery.buildPage();
        ServiceInventoryOutFlowQuery model = serviceInventoryOutFlowQuery.getModel();
        String serviceProviderType = model.getServiceProviderType();
        QueryWrapper<ServiceInventory> wrapper = new QueryWrapper<>();
        wrapper.eq("outf.is_deleted",BusinessConstant.NO)
                .eq("outf.is_enabled",BusinessConstant.YES)
                .like(Strings.isNotBlank(model.getServiceName()),"b.service_name",model.getServiceName())
                .eq(Objects.nonNull(model.getServiceCategoryId()),"a.service_category_id",model.getServiceCategoryId())
                .eq(Objects.nonNull(model.getOutStockType()),"outf.out_stock_type",model.getOutStockType())
                .ge(Objects.nonNull(model.getCreateTimeStart()), "outf.create_time", model.getCreateTimeStart())
                .le(Objects.nonNull(model.getCreateTimeEnd()), "outf.create_time", model.getCreateTimeEnd())
                .eq(Objects.nonNull(model.getServiceProviderType()), "b.service_provider_type", model.getServiceProviderType())
                .eq(Objects.nonNull(model.getServiceProviderId()), "b.service_provider_id", model.getServiceProviderId())
                .eq(Objects.nonNull(model.getExhibitionManageId()), "outf.exhibition_manage_id", model.getExhibitionManageId())
                .orderByDesc("outf.create_time");
        if(Strings.isBlank(serviceProviderType)){
            // 场馆查询
            String keyword = StringUtils.isNotBlank(model.getKeyword()) ? model.getKeyword() : Strings.EMPTY;
            // 查询所有部门
            List<OrganizationVo> data = authServiceFeign.queryList(Collections.emptyList()).getData();
            Map<Long, String> orgMap = data.stream().filter(e -> e.getName().contains(keyword)).collect(Collectors.toMap(OrganizationVo::getId, OrganizationVo::getName));
            Set<Long> orgIds = orgMap.keySet();
            // 查询所有服务商
            List<ServiceProviderVO> serviceProviderVOS = serviceProviderService.listServiceProviderByIds(Collections.emptyList());
            Map<Long, String> serviceProviders = serviceProviderVOS.stream().filter(e -> e.getCompanyName().contains(keyword)).collect(Collectors.toMap(ServiceProviderVO::getId, ServiceProviderVO::getCompanyName));
            Set<Long> providers =serviceProviders.keySet();
            // 查询所有展会
            R<List<ExhibitionManageVO>> allExhibitionManage = exhibitionManageService.queryAllExhibitionManage(ExhibitionManageQuery.builder().build());
            Map<Long, String> exhibitionMap = allExhibitionManage.getData().stream().filter(e -> e.getExhibitionName().contains(keyword)).collect(Collectors.toMap(ExhibitionManageVO::getId, ExhibitionManageVO::getExhibitionName));
            Set<Long> exhibitionManageIds = exhibitionMap.keySet();
            wrapper.eq("b.service_provider_type", DataIsolationSystemSceneEnum.P_COMPOSITE_VENUE.getCode());
            if(StringUtils.isNotBlank(keyword)) {
                wrapper.and(e -> e.or(f -> f.like(StringUtils.isNotBlank(keyword), "b.service_name", model.getKeyword()))
                        .or(StringUtils.isNotBlank(keyword) && CollectionUtils.isNotEmpty(orgIds), f -> f.in("b.service_provider_id", orgIds))
                        .or(StringUtils.isNotBlank(keyword) && CollectionUtils.isNotEmpty(providers), f -> f.in("b.service_provider_id", providers))
                        .or(StringUtils.isNotBlank(keyword) && CollectionUtils.isNotEmpty(exhibitionManageIds), f -> f.in("outf.exhibition_manage_id", exhibitionManageIds)));
            }
            Page<ServiceInventoryOutFlowVO> serviceInventoryOutFlowVOPage = baseMapper.queryOutFlowList(serviceInventoryOutFlowQueryPage, wrapper);
            List<Long> userIds = serviceInventoryOutFlowVOPage.getRecords().stream().map(ServiceInventoryOutFlowVO::getCreatedBy).collect(Collectors.toList());
            UserAccountDto userAccountDto = new UserAccountDto();
            userAccountDto.setUserIds(userIds);
            //获取人员信息
            R<List<UserAccountVo>> listR = userAccountServiceFeign.querySimpleByIds(userAccountDto);
            //把人员信息转成map
            Map<Long, UserAccountVo> userMap = listR.getData().stream().collect(Collectors.toMap(UserAccountVo::getId, Function.identity()));
            for (ServiceInventoryOutFlowVO record : serviceInventoryOutFlowVOPage.getRecords()) {
                record.setCreatedName(Objects.nonNull(userMap.get(record.getCreatedBy()))? userMap.get(record.getCreatedBy()).getRealName():Strings.EMPTY);
                record.setServiceProviderName(Strings.isNotBlank(orgMap.get(record.getServiceProviderId()))? orgMap.get(record.getServiceProviderId()):serviceProviders.get(record.getServiceProviderId()));
                record.setExhibitionManageName(exhibitionMap.get(record.getExhibitionManageId()));
            }
            return serviceInventoryOutFlowVOPage;
        }

        // 主场处理
        wrapper.eq("b.service_provider_type", DataIsolationSystemSceneEnum.P_COMPOSITE_COURT.getCode());
        Page<ServiceInventoryOutFlowVO> resultPage = baseMapper.queryOutFlowList(serviceInventoryOutFlowQueryPage, wrapper);
        List<Long> userIds = resultPage.getRecords().stream().map(ServiceInventoryOutFlowVO::getCreatedBy).collect(Collectors.toList());
        UserAccountDto userAccountDto = new UserAccountDto();
        userAccountDto.setUserIds(userIds);
        //获取人员信息
        R<List<UserAccountVo>> listR = userAccountServiceFeign.querySimpleByIds(userAccountDto);
        //把人员信息转成map
        if(Objects.nonNull(listR) && CollectionUtils.isNotEmpty(listR.getData())){
            Map<Long, UserAccountVo> userMap = listR.getData().stream().collect(Collectors.toMap(UserAccountVo::getId, Function.identity()));
            //获取分类下服务项数量
            if (Objects.nonNull(resultPage.getRecords()) && resultPage.getRecords().size()>0) {
                resultPage.getRecords().forEach((s)->{
                    s.setCreatedName(Objects.nonNull(userMap.get(s.getCreatedBy()))? userMap.get(s.getCreatedBy()).getRealName():Strings.EMPTY);
                });
            }
        }
        return resultPage;
    }

    @Override
    public List<Map<String, Object>> countServiceCategoryOutFlow(Long exhibitionManageId, Long homeId, Integer topN) {
        log.info("countServiceCategoryOutFlow - 统计主场服务分类出库量, exhibitionManageId={}, homeId={}, topN={}", exhibitionManageId, homeId, topN);
        QueryWrapper<ServiceInventoryOutFlow> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("siof.is_deleted", BusinessConstant.DELETE_NO)
                .eq(exhibitionManageId != null, "siof.exhibition_manage_id", exhibitionManageId)
                .eq(homeId != null, "si.service_provider_id", homeId)
                .groupBy("sc.id")
                .orderByDesc("sum(siof.out_num)")
                .last(topN != null, "limit " + topN)
        ;
        List<ServiceInventoryOutFlowVO> serviceInventoryOutFlowList = baseMapper.countServiceCategoryOutFlow(queryWrapper);
        if (serviceInventoryOutFlowList == null || serviceInventoryOutFlowList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> list = serviceInventoryOutFlowList
                .stream()
                .map(serviceInventoryOutFlowVO -> {
                    Map<String, Object> map = new HashMap<>(16);
                    map.put("name", serviceInventoryOutFlowVO.getServiceCategoryName());
                    map.put("value", serviceInventoryOutFlowVO.getOutNum());
                    return map;
                })
                .collect(Collectors.toList());
        return list;
    }

    @Override
    public List<Map<String, Object>> countServiceOutFlow(Long exhibitionManageId, Long homeId, Integer topN) {
        log.info("countServiceOutFlow - 统计主场服务出库量, exhibitionManageId={}, homeId={}, topN={}", exhibitionManageId, homeId, topN);
        QueryWrapper<ServiceInventoryOutFlow> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("siof.is_deleted", BusinessConstant.DELETE_NO)
                .eq(exhibitionManageId != null, "siof.exhibition_manage_id", exhibitionManageId)
                .eq(homeId != null, "si.service_provider_id", homeId)
                .groupBy("si.id")
                .orderByDesc("sum(siof.out_num)")
                .last(topN != null, "limit " + topN)
        ;
        List<ServiceInventoryOutFlowVO> serviceInventoryOutFlowList = baseMapper.countServiceOutFlow(queryWrapper);
        if (serviceInventoryOutFlowList == null || serviceInventoryOutFlowList.isEmpty()) {
            return Collections.emptyList();
        }
        List<Map<String, Object>> list = serviceInventoryOutFlowList
                .stream()
                .map(serviceInventoryOutFlowVO -> {
                    Map<String, Object> map = new HashMap<>(16);
                    map.put("name", serviceInventoryOutFlowVO.getServiceName());
                    map.put("value", serviceInventoryOutFlowVO.getOutNum());
                    return map;
                })
                .collect(Collectors.toList());
        return list;
    }

    @Override
    public void exportServiceCategoryOutFlow(Long exhibitionManageId, Long homeId, HttpServletResponse response) throws IOException {
        log.info("exportServiceCategoryOutFlow - 导出服务分类出库量, exhibitionManageId={}, homeId={}", exhibitionManageId, homeId);
        QueryWrapper<ServiceInventoryOutFlow> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("siof.is_deleted", BusinessConstant.DELETE_NO)
                .eq(exhibitionManageId != null, "siof.exhibition_manage_id", exhibitionManageId)
                .eq(homeId != null, "si.service_provider_id", homeId)
                .groupBy("sc.id")
                .orderByDesc("sum(siof.out_num)")
        ;
        List<ServiceInventoryOutFlowVO> serviceInventoryOutFlowList = baseMapper.countServiceCategoryOutFlow(queryWrapper);
        if (serviceInventoryOutFlowList == null || serviceInventoryOutFlowList.isEmpty()) {
            throw BizException.wrap(1001, "无导出数据");
        }
        List<Map<String, Object>> rows = new ArrayList<>();
        for (ServiceInventoryOutFlowVO contactVO: serviceInventoryOutFlowList) {
            TreeMap<String, Object> map = new TreeMap<>((o1, o2) -> 1);
            map.put("服务分类名称", contactVO.getServiceCategoryName());
            map.put("出库量", contactVO.getOutNum());
            rows.add(map);
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=服务分类排行.xlsx");
        try (ServletOutputStream out = response.getOutputStream()) {
            ExcelUtils.export(rows, out);
        }
    }

    @Override
    public void exportServiceOutFlow(Long exhibitionManageId, Long homeId, HttpServletResponse response) throws IOException {
        log.info("exportServiceOutFlow - 导出服务出库量, exhibitionManageId={}, homeId={}", exhibitionManageId, homeId);
        QueryWrapper<ServiceInventoryOutFlow> queryWrapper = new QueryWrapper<>();
        queryWrapper
                .eq("siof.is_deleted", BusinessConstant.DELETE_NO)
                .eq(exhibitionManageId != null, "siof.exhibition_manage_id", exhibitionManageId)
                .eq(homeId != null, "si.service_provider_id", homeId)
                .groupBy("si.id")
                .orderByDesc("sum(siof.out_num)")
        ;
        List<ServiceInventoryOutFlowVO> serviceInventoryOutFlowList = baseMapper.countServiceOutFlow(queryWrapper);
        if (serviceInventoryOutFlowList == null || serviceInventoryOutFlowList.isEmpty()) {
            throw BizException.wrap(1001, "无导出数据");
        }
        List<Map<String, Object>> rows = new ArrayList<>();
        for (ServiceInventoryOutFlowVO contactVO: serviceInventoryOutFlowList) {
            TreeMap<String, Object> map = new TreeMap<>((o1, o2) -> 1);
            map.put("服务/商品名称", contactVO.getServiceName());
            map.put("出库量", contactVO.getOutNum());
            rows.add(map);
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setHeader("Content-Disposition","attachment;filename=服务商品排行.xlsx");
        try (ServletOutputStream out = response.getOutputStream()) {
            ExcelUtils.export(rows, out);
        }
    }
}
